"""
曲尺的控制台带有内置函数“plot”，该函数在标准的python环境中不可用。
作为一个简单的例子，让我们在二维平面上绘制点（1,1）。

>>> plot((1,1))

你可以按住鼠标左键并移动光标来进行平移，并且可以使用鼠标滚轮进行放大和缩小。
主菜单的“绘图”部分提供了各种操作的选项。

要在三维空间中从原点到点（10,10,10）画一条直线，请使用以下命令

>>> plot([(0,0,0), (10,10,10)])

按住鼠标右键并移动鼠标将旋转视角，WASD键或箭头键可用于移动图像。鼠标滚轮用于缩放整个图像。

参数数据结构
---
‘plot’函数接受任意数量的参数，并且每个参数都将被同时绘制，只要所有参数均为二维或三维。

整数，浮点数，复数或二元组类型的参数会被作为二维点进行绘制，这些类型的对象的列表将绘制为线
来连接每个指定点。 这些类型的对象的列表的列表将被绘制为不同的线。

绘制网格线的函数是complex_grid

>>> from examples import complex_grid
>>> plot(complex_grid())

三元组列表的列表被绘制为实体曲面，但是你必须注意如何排列这些列表，以确保正确处理这些矢量。
将每个三元组列表作为其自变量传递给‘plot’函数，将绘制多条不同的线在三维平面上。

也可以传递一个函数来绘制，该函数返回一个像素数组，通过使用pixelmap关键字参数。

pixelmap使用的一个示例是“区域着色”

>>> from examples import domain_coloring
>>> plot(pixelmap=domain_coloring)

动画像素图从计算方面上来讲非常昂贵，并且“multiprocess”模块用于尝试在后台执行尽可能多的计算。
绘图窗口创建了一个屏幕外的表面用来平移和缩放，并在移动画面后停止1秒钟来重新计算当前位置的像素，
同时还重新计算了背景中的屏幕外表面的像素。 该系统当快速移动时，会遭受一些难以避免的闪烁和
分辨率伪像。

"""
from os import environ
environ["PYGAME_HIDE_SUPPORT_PROMPT"] = "1"
import pygame

from .plot2d import SDLWindow, OPTIONS as OPTIONS_2D
from .plot3d import OpenGLWindow, OPTIONS as OPTIONS_3D
from .util import instanceof

active_window = None
opengl_window = OpenGLWindow()
sdl_window = SDLWindow()

def plot(*args, **kwargs):
	global active_window
	
	window = get_window(*args, **kwargs)

	if not window:
		raise Exception("无效的参数.")
	elif is_active() and window != active_window:
		print(Exception("不能同时绘制2D和3D图形."))
		return
	active_window = window
	active_window.plot(*args, **kwargs)

def is_active():
	return pygame.display.get_init()

def get_window(*args, **kwargs):
	if "pixelmap" in kwargs:
		return sdl_window

	for arg in args:
		if callable(arg):
			return False
		if instanceof(arg, (tuple,list)) and len(arg) == 3 and instanceof(arg[0], list) and instanceof(arg[0][0], (int,float)):
			return opengl_window			
		if instanceof(arg, (int,float,complex)):
			return sdl_window if len(args) > 1 else False
		if instanceof(arg, tuple):
			if len(arg) == 1 and instanceof(arg[0], complex):
				return sdl_window
			if len(arg) == 2 and instanceof(arg[0], (int,float)):
				return sdl_window
			if len(arg) == 3 and instanceof(arg[0], (int,float)):
				return opengl_window
			else:
				return get_window(*arg)
		if instanceof(arg, list):
			if len(arg) == 3 and instanceof(arg[0], list) and len(arg[0]) == len(arg[1]) == len(arg[2]):
				return opengl_window
			return get_window(*arg)
	return False

def config(**kwargs):	
	if kwargs:
		OPTIONS_2D.update(kwargs)
		OPTIONS_3D.update(kwargs)
		if active_window and pygame.get_init():
			active_window.config(**kwargs)
		return
	
	if not active_window: 
		return OPTIONS_2D
	return OPTIONS_2D if active_window == sdl_window else OPTIONS_3D

def animate(delay, callback):
	active_window.animate(delay, callback)

def update(*args, **kwargs):
	if active_window:
		active_window.update(*args, **kwargs)
		return

def close():
	if pygame.display.get_init():
		active_window.close()
